

#include "StateObject.h"

#include <assert.h>

namespace FlameEngine
{	
#pragma region RasterizerState
	//-----------------rasterizer state-----------------------
	//RasterizerStateDesc member
	uint32_t RasterizerStateDesc::CalcHashCode() const
	{
		uint32_t result = 0;
		uint32_t temp;
		if(depthBias != 0)
		{
			result = depthBias + 0x7ed55d16 + (depthBias<<12);
		}
		if(depthBiasClamp != 0)
		{
			temp = *((uint32_t*)&depthBiasClamp);
			result = result ^ 0xc761c23c ^ (temp<<19);
		}
		if(slopeScaledDepthBias != 0)
		{
			temp = *((uint32_t*)&slopeScaledDepthBias);
			result = result + 0xfd7046c5 + (temp << 9);
		}

		result <<= 10;
		result &= 0xFFFFFC0C;
		result ^= (uint32_t)counterClockwiseFrontFace;
		result ^= (depthClipEnable<<1);
		result ^= (scissorEnable<<2);
		result ^= (multisampleEnable<<3);		
		result ^= (antialiasedLineEnable<<4);
		result ^= (fillMode<<5);
		result ^= (cullMode<<6);
		return result;
	}
	
	//Rasterizer State member
	RasterizerState::RasterizerState()
		:m_isDirty(true),m_hashCode(0)
	{
	}

	RasterizerState::RasterizerState(const RasterizerStateDesc& _desc)
		:m_isDirty(true),m_stateDesc(_desc),m_hashCode(0)
	{
	}
	
	void RasterizerState::SetFillMode(FillMode _value)
	{
		m_isDirty = (GetFillMode() == _value)?false:true;
		m_stateDesc.fillMode = _value;
	}

	void RasterizerState::SetCullMode(CullMode _value)
	{
		m_isDirty = (GetCullMode() == _value)?false:true;
		m_stateDesc.cullMode = _value;		
	}

	void RasterizerState::SetDepthBias(int32_t _value)
	{
		m_isDirty = (GetDepthBias() == _value)? false:true;
		m_stateDesc.depthBias = _value;
	}

	void RasterizerState::SetDepthBiasClamp(float _value)
	{
		m_isDirty = (GetDepthBiasClamp() == _value)?false:true;
		m_stateDesc.depthBiasClamp = _value;
	}

	void RasterizerState::SetSlopeScaledDepthBias(float _value)
	{
		m_isDirty = (GetSlopeScaledDepthBias() == _value)?false:true;
		m_stateDesc.slopeScaledDepthBias = _value;
	}

	void RasterizerState::SetDepthClipEnable(bool _value)
	{
		m_isDirty = (IsDepthClipEnable() == _value)?false:true;
		m_stateDesc.depthClipEnable = _value;
	}

	void RasterizerState::SetScissorEnable(bool _value)
	{
		m_isDirty = (IsScissorEnable() == _value)?false:true;
		m_stateDesc.scissorEnable = _value;
	}

	void RasterizerState::SetMultisampleEnable(bool _value)
	{
		m_isDirty = (IsMultisampleEnable() == _value)?false:true;
		m_stateDesc.multisampleEnable = _value;
	}

	void RasterizerState::SetAntialiasedLineEnalbe(bool _value)
	{
		m_isDirty = (IsAntialiasedLineEnable() == _value)?false:true;
		m_stateDesc.antialiasedLineEnable = _value;
	}

	void RasterizerState::SetCounterClockwiseFrontFace(bool _value)
	{
		m_isDirty = (IsCounterClockwiseFrontFace() == _value)?false:true;
		m_stateDesc.counterClockwiseFrontFace = _value;
	}


#pragma endregion

#pragma region DepthStencilState
	//depth stencil desc member
	uint32_t DepthStencilStateDesc::CalcHashCode() const
	{
		uint32_t result;
		result = ffStencilFailOp;
		result ^= (ffStencilDepthFailOp << 4);
		result ^= (ffStencilFunction << 8);
		result ^= (ffStencilPassOp << 12);
		result ^= (bfStencilFailOp << 16);
		result ^= (bfStencilDepthFailOp << 20);
		result ^= (bfStencilFunction << 24);
		result ^= (bfStencilPassOp << 28);

		result += stencilReadMask * 0xd3a2646c;
		result += stencilWriteMask * 0xfd7046c5;
		result += depthWriteMask * 0xfd7046c5;
		result <<= 3;
		result += depthFunciton * 0xb55a4f09;
		result <<= 2;
		result ^= (uint32_t)depthEnable;
		result ^= (stencilEnable << 1);
		return result;
	}

	//-----------------depth stencil state--------------------------
	DepthStencilState::DepthStencilState()
		:m_isDirty(true),m_hashCode(0)
	{
	}

	DepthStencilState::DepthStencilState(const DepthStencilStateDesc& _desc)
		:m_isDirty(true),m_stateDesc(_desc),m_userData(-1),m_hashCode(0)
	{
	}

	void DepthStencilState::SetDepthEnable(bool enable)
	{
		m_isDirty = (IsDepthEnable() == enable)?false:true;
		m_stateDesc.depthEnable = enable;
	}

	void DepthStencilState::SetDepthWriteMask(DepthWriteMask mask)
	{
		m_isDirty = (GetDepthWriteMask() == mask)?false:true;
		m_stateDesc.depthWriteMask = mask;
	}

	void DepthStencilState::SetDepthFunction(CompareFunction func)
	{
		m_isDirty = (GetDepthFunction() == func)?false:true;
		m_stateDesc.depthFunciton = func;
	}

	void DepthStencilState::SetStencilEnable(bool enable)
	{
		m_isDirty = (IsStencilEnable() == enable)?false:true;
		m_stateDesc.stencilEnable = enable;
	}

	void DepthStencilState::SetStencilReadMask(uint8_t mask)
	{
		m_isDirty = (GetStencilReadMask() == mask)?false:true;
		m_stateDesc.stencilReadMask = mask;
	}

	void DepthStencilState::SetStencilWriteMask(uint8_t mask)
	{
		m_isDirty = (GetStencilWriteMask() == mask)?false:true;
		m_stateDesc.stencilWriteMask = mask;
	}

	void DepthStencilState::SetFFStencilFailOperation(StencilOperation op)
	{
		m_isDirty = (GetFFStencilFailOperation() == op)?false:true;
		m_stateDesc.ffStencilFailOp = op;
	}

	void DepthStencilState::SetFFStencilDepthFailOperation(StencilOperation op)
	{
		m_isDirty = (GetFFStencilDepthFailOperation() == op)?false:true;
		m_stateDesc.ffStencilDepthFailOp = op;
	}

	void DepthStencilState::SetFFStencilPassOperation(StencilOperation op)
	{
		m_isDirty = (GetFFStencilPassOperation() == op)?false:true;
		m_stateDesc.ffStencilPassOp = op;
	}

	void DepthStencilState::SetFFStencilFunc(CompareFunction func)
	{
		m_isDirty = (GetFFStencilFunc() == func)?false:true;
		m_stateDesc.ffStencilFunction = func;
	}

	void DepthStencilState::SetBFStencilFailOperation(StencilOperation op)
	{
		m_isDirty = (GetBFStencilFailOperation() == op)?false:true;
		m_stateDesc.bfStencilFailOp = op;
	}

	void DepthStencilState::SetBFStencilDepthFailOperation(StencilOperation op)
	{
		m_isDirty = (GetBFStencilDepthFailOperation() == op)?false:true;
		m_stateDesc.bfStencilDepthFailOp = op;
	}

	void DepthStencilState::SetBFStencilPassOperation(StencilOperation op)
	{
		m_isDirty = (GetBFStencilPassOperation() == op)?false:true;
		m_stateDesc.bfStencilPassOp = op;
	}

	void DepthStencilState::SetBFStencilFunc(CompareFunction func)
	{
		m_isDirty = (GetBFStencilFunc() == func)?false:true;
		m_stateDesc.bfStencilFunction = func;
	}
#pragma endregion

#pragma region BlendState
	//-------------------------blend state-----------------------------------
	//BlendStateDesc
	uint32_t BlendStateDesc::CalcHashCode() const
	{
		uint32_t result = 0;
		if(independentBlendEnable)
		{
			uint32_t *packedValue = (uint32_t*)(RTBlendDesc*)rtBlendState;
			for (int i = 0;i < maxRTCount; i++)
			{
				result = result * 13131 + packedValue[i];
			}
		}
		else
		{
			uint32_t packedValue = *((uint32_t*)&rtBlendState);
			result = (0x7ed55d16 + packedValue) ^ (packedValue + 0xfd7046c5);
		}
		result >>= 2;
		result |= (alphaToCoverageEnable << 31);
		result |= (independentBlendEnable << 30);
		return result;
	}	
	
	//BlendState
	BlendState::BlendState()
		:m_isDirty(true),m_hashCode(0)
	{
	}

	BlendState::BlendState(const BlendStateDesc& desc)
		:m_isDirty(true),m_hashCode(0),m_stateDesc(desc)
	{
	}

	void BlendState::SetAlphaToCoverageEnable(bool enable)
	{
		m_isDirty = (IsAlphaToCoverageEnable() == enable)?false:true;
		m_stateDesc.alphaToCoverageEnable = enable;
	}

	void BlendState::SetIndependentBlendEnable(bool enable)
	{
		m_isDirty = (IsIndependentBlendEnable() == enable)?false:true;
		m_stateDesc.independentBlendEnable = enable;
	}

	void BlendState::SetBlendEnable(bool enable,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;
		
		m_isDirty = (IsBlendEnable(rtIndex) == enable)?false:true;
		m_stateDesc.rtBlendState[rtIndex].blendEnable = enable;
	}

	void BlendState::SetSourceBlend(Blend blend,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetSourceBlend(rtIndex) == blend)?false:true;
		m_stateDesc.rtBlendState[rtIndex].srcBlend = blend;
	}

	void BlendState::SetDestBlend(Blend blend,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetDestBlend(rtIndex) == blend)?false:true;
		m_stateDesc.rtBlendState[rtIndex].destBlend = blend;
	}

	void BlendState::SetSourceBlendAlpha(Blend blend,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetSourceBlendAlpha(rtIndex) == blend)?false:true;
		m_stateDesc.rtBlendState[rtIndex].srcBlendAlpha = blend;			
	}

	void BlendState::SetDestBlendAlpha(Blend blend,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetDestBlendAlpha(rtIndex) == blend)?false:true;
		m_stateDesc.rtBlendState[rtIndex].destBlendAlpha = blend;
	}

	void BlendState::SetBlendOperation(BlendOperation op,uint8_t rtIndex)
	{
		if(rtIndex >= BlendStateDesc::maxRTCount)
			return;
		
		m_isDirty = (GetBlendOperation(rtIndex) == op)?false:true;
		m_stateDesc.rtBlendState[rtIndex].blendOp = op;
	}

	void BlendState::SetAlphaOperation(BlendOperation op,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetAlphaOperation(rtIndex) == op)?false:true;
		m_stateDesc.rtBlendState[rtIndex].blendOpAlpha = op;
	}

	void BlendState::SetRenderTargetWriteMask(RTWriteMaskFlag mask,uint8_t rtIndex)
	{
		if(rtIndex > BlendStateDesc::maxRTCount)
			return;

		m_isDirty = (GetRenderTargetWriteMask(rtIndex) == mask)?false:true;
		m_stateDesc.rtBlendState[rtIndex].writeMask = mask;
	}
#pragma endregion

#pragma region SamplerState
	//--------------------------sampler state-----------------------------
	//SamplerDesc
	uint32_t SamplerDesc::CalcHashCode() const
	{
		uint32_t result = 0;
		result = MipLodBias;
		result |= (MaxAnisotropy << 8);
		result |= (MinLod << 16);
		result |= (MaxLod << 24);
		result *= 0x7ed55d16;

		uint32_t temp;
		temp = Filter;
		temp |= (AddressModeU<<5);
		temp |= (AddressModeV<<8);
		temp |= (AddressModeW<<11);
		temp |= (CompareFunc<<14);
		temp = temp + 0xfd7046c5 + (temp<<3);
		result += temp;

		temp =0;
		temp =  *((uint32_t*)&BorderColor.x)* 1313;
		temp += *((uint32_t*)&BorderColor.y)* 13131;
		temp += *((uint32_t*)&BorderColor.z)* 131313;
		temp += *((uint32_t*)&BorderColor.w)* 1313131;
		result += temp;
		return result;
	}

	//SamplerState
	SamplerState::SamplerState()
		:m_isDirty(true),m_hashCode(0)
	{
	}

	SamplerState::SamplerState(const SamplerDesc& desc)
		:m_isDirty(true),m_hashCode(0),m_stateDesc(desc)
	{
	}

	void SamplerState::SetFilter(TextureFilter filter)
	{
		m_isDirty = (GetFilterType() == filter)?false:true;
		m_stateDesc.Filter = filter;
	}

	void SamplerState::SetAddressModeU(TextureAddressMode mode)
	{
		m_isDirty = (GetAddressModeU() == mode)?false:true;
		m_stateDesc.AddressModeU = mode;
	}

	void SamplerState::SetAddressModeV(TextureAddressMode mode)
	{
		m_isDirty = (GetAddressModeV() == mode)?false:true;
		m_stateDesc.AddressModeV = mode;
	}

	void SamplerState::SetAddressModeW(TextureAddressMode mode)
	{
		m_isDirty = (GetAddressModeW() == mode)?false:true;
		m_stateDesc.AddressModeW = mode;
	}

	void SamplerState::SetLodBias(uint8_t bias)
	{
		m_isDirty = (GetMipLodBias() == bias)?false:true;
		m_stateDesc.MipLodBias = bias;
	}

	void SamplerState::SetMinLod(uint8_t minLod)
	{
		m_isDirty = (GetMinLod() == minLod)?false:true;
		m_stateDesc.MinLod = minLod;
	}

	void SamplerState::SetMaxLod(uint8_t maxLod)
	{
		m_isDirty = (GetMaxLod() == maxLod)?false:true;
		m_stateDesc.MaxLod = maxLod;
	}

	void SamplerState::SetBorderColor(const Float4& color)
	{
		m_isDirty = (m_stateDesc.BorderColor == color)?false:true;
		m_stateDesc.BorderColor = color;
	}

	void SamplerState::SetCompareFunction(CompareFunction func)
	{
		m_isDirty = (GetComparisonFunc() == func)?false:true;
		m_stateDesc.CompareFunc = func;
	}
#pragma endregion
}
